package util

import (
	"sync"
	"time"
)

const CleanupInterval  = 20*time.Second  //20秒清理一次缓存中到期的key

type checker struct {
	Interval time.Duration
}

type Item struct {
	Object     interface{}
	Expiration int64
}

type cache struct {
	items             map[string]Item
	mu                sync.RWMutex
	checker           *checker
}

func New() *cache{
	items := make(map[string]Item)
	c := &cache{
		items:      items,
	}
	runChecker(c,CleanupInterval)
	return c
}

func runChecker(c *cache, ci time.Duration) {
	ch := &checker{
		Interval: ci,
	}
	c.checker = ch
	go ch.Run(c)
}

func (ch *checker) Run(c *cache) {
	ticker := time.NewTicker(ch.Interval)
	for {
		select {
		case <-ticker.C:
			c.DeleteExpired()
		}
	}
}

func (c *cache) DeleteExpired() {
	now := time.Now().UnixNano()
	for k, v := range c.items {
		if v.Expiration > 0 && now > v.Expiration {
			c.Delete(k)
		}
	}
}

func (c *cache) Set(k string, x interface{}, d time.Duration) {
	var e int64
	if d > 0 {
		e = time.Now().Add(d).UnixNano()
	}
	c.mu.Lock()
	c.items[k] = Item{
		Object:     x,
		Expiration: e,
	}
	c.mu.Unlock()
}

func (c *cache) Get(k string) (interface{}) {
	c.mu.RLock()
	item, found := c.items[k]
	if !found {
		c.mu.RUnlock()
		return nil
	}
	if item.Expiration > 0 {
		if time.Now().UnixNano() > item.Expiration {
			c.mu.RUnlock()
			return nil
		}
	}
	c.mu.RUnlock()
	return item.Object
}

func (c *cache) Replace(k string, x interface{}, d time.Duration) error {
	c.Set(k, x, d)
	return nil
}

func (c *cache) Delete(k string) {
	c.mu.Lock()
	delete(c.items, k)
	c.mu.Unlock()
}

